package com.wujilee.orderservice.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.retailstore.model.OrderInfo;
import com.wujilee.dbentity.common.OrderStatus;
import com.wujilee.dbentity.common.PayStatus;
import com.wujilee.dbentity.entity.EntityOrderInfo;
import com.wujilee.dbentity.entity.EntityPaymentInfo;
import com.wujilee.dbentity.mapper.EntityOrderInfoGeneratedMapper;
import com.wujilee.dbentity.mapper.EntityPaymentInfoGeneratedMapper;
import com.wujilee.orderservice.service.OrderService;
import com.wujilee.payservice.service.PayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.yaml.snakeyaml.constructor.DuplicateKeyException;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.UUID;

/**
 * @author liwuji
 * @date 2024/6/17
 * @desc
 **/
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Resource
    private PayService payService;
    @Resource
    private EntityPaymentInfoGeneratedMapper paymentInfoMapper;

    @Resource
    private EntityOrderInfoGeneratedMapper orderInfoGeneratedMapper;


    @Override
    public EntityOrderInfo creatOrder(Long userId, String payType) {
        EntityOrderInfo orderInfo = new EntityOrderInfo();
        String no = UUID.randomUUID().toString().replaceAll("-", "");
        orderInfo.setOrderNo(no);
        orderInfo.setOrderStatus(OrderStatus.INIT);
        orderInfo.setPayStatus(PayStatus.NO_PAY);
        orderInfo.setIsDeleted(0);
        orderInfo.setCreateTime(new Date());
        orderInfoGeneratedMapper.insert(orderInfo);
        return orderInfo;
    }

    @Override
    public String pay(Long id) {
        EntityOrderInfo orderInfoById = getOrderInfoById(id);
        if (orderInfoById.getCodeUrl() != null) {
            return orderInfoById.getCodeUrl();
        }
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setOutTradeNo(orderInfoById.getOrderNo());
        orderInfo.setTotalFee(1L);
        String url = payService.nativePayOrder(orderInfo);
        orderInfoById.setCodeUrl(url);
        saveCodeUrl(id, url);
        return url;
    }

    @Override
    public EntityOrderInfo getOrderInfoById(Long id) {
        LambdaQueryWrapper<EntityOrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(EntityOrderInfo::getId, id)
                .eq(EntityOrderInfo::getIsDeleted, 0);
        EntityOrderInfo entityOrderInfo = orderInfoGeneratedMapper.selectOne(queryWrapper);
        if (entityOrderInfo == null) {
            throw new RuntimeException("订单不存在或已被删除！");
        }
        return entityOrderInfo;
    }

    @Override
    public EntityOrderInfo getOrderInfoByNo(String orderNo) {
        LambdaQueryWrapper<EntityOrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(EntityOrderInfo::getOrderNo, orderNo)
                .eq(EntityOrderInfo::getIsDeleted, 0);
        EntityOrderInfo entityOrderInfo = orderInfoGeneratedMapper.selectOne(queryWrapper);
        if (entityOrderInfo == null) {
            throw new RuntimeException("订单不存在或已被删除！");
        }
        return entityOrderInfo;
    }
    
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveCodeUrl(Long id, String codeUrl) {
        LambdaUpdateWrapper<EntityOrderInfo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(EntityOrderInfo::getCodeUrl, codeUrl)
                .eq(EntityOrderInfo::getId, id)
                .isNull(EntityOrderInfo::getCodeUrl);
        int update = orderInfoGeneratedMapper.update(null, updateWrapper);
        if (update == 0) {
            throw new RuntimeException("更新失败，请稍后再试！");
        }
    }

    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void notifyOrder(Transaction transaction) {
        // 这里可以有一个通知接收表 用于出现问题时的查询
        
        // 这里存在并发问题 -- 解决方案- 订单id+订单号形成联合索引
        String outTradeNo = transaction.getOutTradeNo();
        EntityOrderInfo orderInfoByNo = getOrderInfoByNo(outTradeNo);
        EntityPaymentInfo entityPaymentInfo = new EntityPaymentInfo();
        entityPaymentInfo.setOrderNo(entityPaymentInfo.getOrderNo());
        entityPaymentInfo.setOrderId(orderInfoByNo.getId());
        entityPaymentInfo.setPaymentType(true);
        entityPaymentInfo.setPaymentStatus(transaction.getTradeState().ordinal());
        entityPaymentInfo.setTradeNo(transaction.getTransactionId());
        entityPaymentInfo.setTotalAmount(new BigDecimal(transaction.getAmount().getTotal()));
        // 这里一帮要做订单编号的校验 支付金额的校验
        try {
            paymentInfoMapper.insert(entityPaymentInfo);
        } catch (DuplicateKeyException e) {
            log.info("该订单已接收到支付通知", e);
        }
        LambdaUpdateWrapper<EntityOrderInfo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper
                .set(EntityOrderInfo::getPayStatus, PayStatus.PAY)
                .in(EntityOrderInfo::getOrderStatus, Arrays.asList(OrderStatus.TIME_OUT, OrderStatus.INIT))
                .eq(EntityOrderInfo::getPayStatus, PayStatus.NO_PAY)
                .eq(EntityOrderInfo::getId, orderInfoByNo.getId());
        int update = orderInfoGeneratedMapper.update(null, updateWrapper);
        if(update != 1){
            throw new RuntimeException("更新支付状态失败，orderId"+orderInfoByNo.getId());
        }
    }
}
